import pydot
import networkx as nx


def get_graph_class(graph, cls):
    for node in graph.nodes():
        if isinstance(graph.nodes[node]['data'], cls):
            return graph.nodes[node]['data']


def get_nodes_with_zero_out_degree(graph):
    nodes_data = []
    for node in graph.nodes():
        if graph.out_degree(node) == 0:
            nodes_data.append(graph.nodes[node]['data'])
    return nodes_data


def remove_zero_degree_nodes(G):
    # 找到出度和入度都为 0 的节点
    zero_degree_nodes = [node for node in G.nodes() if G.out_degree(node) == 0 and G.in_degree(node) == 0]

    # 删除出度和入度都为 0 的节点
    for node in zero_degree_nodes:
        G.remove_node(node)

    return G


def count_nodes_from_file(dot_file_path):
    # 使用pydot加载.dot文件
    graphs = pydot.graph_from_dot_file(dot_file_path)

    # pydot返回的是图列表，通常我们的.dot文件包含一个图
    graph = graphs[0]

    # 获取图中的节点列表
    nodes = graph.get_nodes()

    # 初始化有效节点计数
    valid_node_count = 0

    # 遍历节点，验证它们是否是有效的节点
    for node in nodes:
        # 检查节点是否包含标签或形状属性，这通常表示它是一个有效的节点
        if node.get_label() is not None or 'shape' in node.get_attributes():
            valid_node_count += 1

    # 返回有效节点数量
    return valid_node_count


def check_edge_and_get_label(graph, node1, node2):
    if graph.has_edge(node1, node2):
        return graph[node1][node2].get('label', "")
    else:
        return ""


def split_graph_into_components(graph):
    """
    拆分无向图为若干个相互独立的子图。

    参数:
        graph (nx.Graph): 输入的无向图

    返回:
        List[nx.Graph]: 包含每个连通分量的子图列表
    """
    # 检查图是否为无向图
    if not isinstance(graph, nx.Graph):
        raise TypeError("输入图必须是无向图(nx.Graph)。")

    # 获取连通分量
    components = list(nx.connected_components(graph))

    # 将连通分量转换为独立的子图
    subgraphs = [graph.subgraph(component).copy() for component in components]

    return subgraphs

def remove_zero_degree_nodes_no_direction(G):
    # 找到度为 0 的节点
    zero_degree_nodes = [node for node in G.nodes() if G.degree(node) == 0]

    # 删除度为 0 的节点
    for node in zero_degree_nodes:
        G.remove_node(node)

    return G
